(defmeth log-linear-proto ::print-zero-data-problems (window)
  (let* ((w window)
         (general-explanation (format nil "Warning: As consequence of sampling zeros the fitted model includes ~d fitted zeros. ~%This may result in problems with the degrees of freedom of the model ~%and with the estimation of coefficients of parameters." (send self :num-fitted-zeros)))
         (efective-dimen-x-matrix (send self :efective-dimen-xmatrix))
         (efective-df (- (first efective-dimen-x-matrix) (second efective-dimen-x-matrix)))
         (explanation-degrees-of-freedom (format nil "~%~%The design matrix has originally ~d rows and ~d columns or coefficients.~%If the fitted zeros are not considered this results in ~d degrees of freedom.~%However, after removing the rows with fitted zeros the model matrix has ~d rows and a column rank of ~d. ~%According to Clogg & Eliason, 1987, this results in ~d degrees of freedom.   "
                                                 (array-dimension (send self :x-matrix) 0)
                                                 (array-dimension (send self :x-matrix) 1)
                                                 (send self :df)
                                                 (first efective-dimen-x-matrix) 
                                                 (second efective-dimen-x-matrix) 
                                                 efective-df ))
         (fit (format nil "~%Deviance=   ~,5f df=  ~d p= ~,5f ~%Chi-Square= ~,5f df=  ~d p= ~,5f ~%AIC ~,5g ~%BIC ~,5f  "
                      (send self :deviance) 
                      efective-df 
                      (if (> efective-df 0) (- 1 (chisq-cdf (send self :deviance) efective-df)) nil)
                      (send self :chi) 
                      efective-df 
                      (if (> efective-df 0) (- 1 (chisq-cdf (send self :chi) efective-df)) nil)
                      (send self :efective-aic) 
                      (send self :efective-bic)))
         (explanation-coefficients (format nil "~%~%The model tested has ~d coefficientes of parameters equal to zero by design. ~%Therefore, the values printed by the program for these parameters SHOULD BE INTERPRETED VERY CAREFULLY." (send self :num-zero-coefs nil)))
         (zero-coefs (format nil "~%~%The parameter(s) equal to zero are:~% ~A" 
                             (format nil (apply 'strcat (mapcar #'(lambda (coef) (strcat "~%" coef)) 
                                                                (send self :zero-coefs nil ))))))
         (explanation-excluded-zero-coefs (format nil "~%~%There are ~d parameter(s) that have been excluded from the model to avoid redundancy ~%but will result in coeficient(s) equal to zero if are included by changing the categories of reference. ~%Also, if they are reference categories for terms in the model, wrong coefficientes for the terms will be produced." (- (send self :num-zero-coefs t) (send self :num-zero-coefs nil))))
         (dif-parameter (set-difference (send self :zero-coefs t ) 
                                        (send self :zero-coefs nil )
                                        :test 'equal))
         (excluded-zero-coefs (format nil "~%~%These Parameters are:~% ~A" 
                                      (format nil (apply 'strcat (mapcar #'(lambda (coef) (strcat "~%" coef)) 
                                                                dif-parameter)))))
         (explanation-zero-parameters (format nil "~%~%The zero parameters will make that other parameters also have wrong parameter estimations. ~%You may detect these parameters checking those with coefficientes and/or standard errors unusually small or big.")))
    (display-string (strcat general-explanation explanation-degrees-of-freedom fit) w)
    (when (send self :zero-coefs nil ) (display-string (strcat explanation-coefficients zero-coefs) w))
    (when dif-parameter (display-string (strcat explanation-excluded-zero-coefs excluded-zero-coefs) w))
  (display-string explanation-zero-parameters w)
  ))


;que ocurre cuando el fitted zero está en la categoría de referencia nada más? Tengo que probarlo

(defmeth log-linear-proto :num-non-zero-coefs ()

  (- (send self :num-coefs) (send self :num-zeroes)))


(defmeth log-linear-proto :num-var ()
  (length (send self :set-ncat)))



(defmeth log-linear-proto :efective-dimen-saturated-xmatrix (&optional (zero 0.000000001))
  (let* ((fitted-zeros (send self :fitted-zeros))
         )
    
    (cond 
      (fitted-zeros
       (setf m (apply 'bind-rows (select (row-list (send self :saturated-xmatrix))
                                             (set-difference (iseq (send self :num-cases))  fitted-zeros :test #'=))))
       (count zero (eigenvalues (cross-product m)) :test #'<))
      (t 
       (apply '* (send self :set-ncat))))))

      
(defmeth log-linear-proto :efective-dimen-xmatrix (&optional (zero 0.000000001))
  "Outputs the efective dimensionality of the model matrix. Clogg & Eliason 1987"
  (let* ((fitted-zeros (send self :fitted-zeros))
         (matrix (send self :x-matrix))
         )
    (cond 
      (fitted-zeros
       (setf m (apply 'bind-rows (select (row-list matrix )
                                             (set-difference (iseq (send self :num-cases))  fitted-zeros :test #'=))))
       
       (list (array-dimension m 0) (count zero (eigenvalues (cross-product m)) :test #'<)))
      (t 
       (array-dimensions matrix )))))



(defmeth log-linear-proto :efective-df ()
  (let ((ef-dim (send self :efective-dimen-xmatrix))
        )
    (- (first ef-dim) (second ef-dim))))

#|(defmeth log-linear-proto :zero-reference-categories ()
  (let* ((x-matrix (send self :complete-xmatrix))
         (y-var (send self :yvar))
         (margin (mapcar #'(lambda (col) (sum (* col y-var))) (column-list x-matrix)))
         (where-zeroes (which (mapcar #'(lambda (val)  (= 0 val)) margin)))
         (pred 
          (when where-zeroes
                (select (send self :complete-predictor-names)
                        where-zeroes)))
         (zero-reference-categories (set-difference pred (send self :zero-coefs) :test #'equal ))
         )
       zero-reference-categories))|#

(defmeth log-linear-proto :zero-coefs (&optional (complete nil))
"Generates the names of coeficientes that are zero in the matrix. Arg complete controls if it prints coefficientes excluded in the design matrix"
  (let* ((x-matrix (if complete (send self :complete-xmatrix)
                       (send self :x)))
         (y-var (send self :yvar))
         (margin (mapcar #'(lambda (col) (sum (* col y-var))) (column-list x-matrix)))
         (where-zeroes (which (mapcar #'(lambda (val)  (= 0 val)) margin)))
         (predict-names (if complete (send self :complete-predictor-names)
                            (send self :predictor-names)))
         (pred 
          (when where-zeroes
                (select predict-names
                        where-zeroes)))
         )
        pred))

(defmeth log-linear-proto :id-zero-coefs (&optional (complete nil))
"Outputs the position of the zero coefs in the list of predictor names excluding the constant"
  (let* ((x-matrix (if complete (send self :complete-xmatrix)
                       (send self :x)))
         (y-var (send self :yvar))
         (margin (mapcar #'(lambda (col) (sum (* col y-var))) (column-list x-matrix)))
         (where-zeroes (which (mapcar #'(lambda (val)  (= 0 val)) margin)))
         )
        where-zeroes))

(defmeth log-linear-proto :num-zero-coefs (&optional (complete nil))
  (length (send self :zero-coefs complete)))


;; De este método, la parte de non-identified coincide con los parámetros no identificados
;; que le salen a vermunt asi que esa parte parece que la tengo localizada.
;; Ahora lo que me falta es averiguar qué parámetros son los que debería eliminar
;; Parece que eso se hace porque convergen hacia cero
;; TAmbién tengo que averiguar la fórmula que utiliza en concreto.


(defmeth log-linear-proto :num-non-identified-coefs (&optional (zero 0.000000001))
  (let ((m (apply 'bind-rows (select (row-list (send self :x))
                                              (which (mapcar #'(lambda (f) (< 0 f)) (send self :yvar)))))))
   ; (print (eigenvalues (cross-product m)))
   
   (count zero (eigenvalues (cross-product m)) :test #'>)))

(defmeth log-linear-proto :fitted-zeros (&optional (zero 0.001))
  (which (mapcar #'(lambda (y) (< y zero)) (send self :fit-means))))


(defmeth log-linear-proto :num-fitted-zeros (&optional (zero 0.001))
  (count zero (send self :fit-means) :test #'>))

(defmeth log-linear-proto :num-sampling-zeros ()
  (count 0 (send self :yvar) :test #'=))
  
(defmeth log-linear-proto :sampling-zeros ()
  (which (mapcar #'(lambda (y) (= y 0)) (send self :yvar))))

#|(defmeth log-linear-proto :compute-non-redundant-parameters ()
  (let* ((zero 0.00000001)
         (fitted-zeros (count 0.0001 (send self :fit-means) :test #'>))
         (M-matrix (apply 'bind-rows (select (row-list (transpose (send self :complete-xmatrix)))
                                              (which (mapcar #'(lambda (f) (< zero f)) (send self :yvar))))))
         (num-maximo-parameters (count zero (eigenvalues (covariance-matrix (transpose (send self :complete-xmatrix)))) :test #'<))
         (num-maximo-parameters (count zero  (eigenvalues (covariance-matrix M-matrix)) :test #'<)))
    (break)
    (print "like always")
    (print (- (length (send self :yvar)) (send self :num-coefs)))
    (print "new test")
    (print (- num-par (- (send self :num-coefs) fitted-zeros)))
    (print (- num-par2 (- (send self :num-coefs) fitted-zeros)))
    (print "num pos parameters - numparameters")
  
    (print (- (- (length (send self :yvar)) num-par) (send self :num-coefs)))
    (print (- (- (length (send self :yvar)) num-par2) (send self :num-coefs)))
    (print "fitted-zeros")
    (print fitted-zeros)
    (print "numpar")
    (print num-par)
    (print "non-identified")
    (print (1- (- (send self :num-coefs) num-par2)))
    (print "eigen")
    (print (eigenvalues (covariance-matrix M-matrix)))
    (print "Clogg")
     (print (- (- (length (send self :yvar))
              fitted-zeros)
              num-par))
    (print "adjusted est df-sas")
    (print (- (- (length (send self :yvar))
              fitted-zeros)
              num-par))))|#